package top.superflow.core.config

import top.superflow.core.metadata.MetadataAble
import top.superflow.core.statis.Metrizable
import top.superflow.core.statis.imp.MapStatistics

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{Future, Promise}

abstract class DefaultConfigurable[C <: MetadataAble] extends Configurable[C] {

  private var config : C = _

  def getConfig: C = this.config

  protected val setupConfigInFutureFun = new Function3[DefaultConfigurable[C],C, Function2[DefaultConfigurable[C], C, Metrizable[_]], Future[Metrizable[_]]] {
    def apply(configWrapper:DefaultConfigurable[C], config: C, func: Function2[DefaultConfigurable[C], C, Metrizable[_]]): Future[Metrizable[_]] = {
      if (func == null) {
        throw new IllegalArgumentException("Input func should not be null!")
      }

      val p = Promise[Metrizable[_]]()
      Future {
        val resultStatis = func.apply(configWrapper,config)

        p success resultStatis
      }
      p.future
    }
  }

  protected val setupConfigAsynFun = new Function2[DefaultConfigurable[C], C, Metrizable[_]] {
    def apply(configWrapper: DefaultConfigurable[C], config: C): Metrizable[_] = {
      configWrapper.setConfig(config)
      MapStatistics.getStatistics(configWrapper.getConfig)
    }
  }

  protected def setConfig(config : C): Unit = {
    this.config = config
  }

  //pool manager configuration
  def initialize(config: C): Future[Metrizable[_]] = {
    setupConfigInFutureFun.apply(this, config, setupConfigAsynFun)
  }

  def reset: Future[Metrizable[_]] = {
    setupConfigInFutureFun.apply(this, this.getConfig, setupConfigAsynFun)
  }

  def hotApply(config: C): Future[Metrizable[_]] = {
    setupConfigInFutureFun.apply(this, config, setupConfigAsynFun)
  }
}